#include "common.h"
#include "dma.h"

int dma_memory_init(int8_t ch, uint32_t *sar, uint32_t volatile *dar, uint32_t byte, uint8_t ssize, uint8_t dsize, uint8_t trans_t){
    /* check legallity of input */
    if(ch<DMA_CH0||ch>DMA_CH3)
        return -1;

    /* enable clock gating */
    SIM_SCGC6|=SIM_SCGC6_DMAMUX_MASK; // Enable DMAMUX clock gating
    SIM_SCGC7|=SIM_SCGC7_DMA_MASK; // Enable DMA clock gating

    /* clear pending errors or acknowledge successful transfers */
    DMA_DSR_BCR_REG(DMA_BASE_PTR, ch)|=DMA_DSR_BCR_DONE_MASK;

    /* repeat to confirm */
    DMA_DSR_BCR_REG(DMA_BASE_PTR, ch)|=DMA_DSR_BCR_DONE_MASK;

    /* write source address, destination address, status/byte count */
    DMA_SAR_REG(DMA_BASE_PTR, ch)|=DMA_SAR_SAR(sar);
    DMA_DAR_REG(DMA_BASE_PTR, ch)|=DMA_DAR_DAR(dar);
    DMA_DSR_BCR_REG(DMA_BASE_PTR, ch)|=DMA_DSR_BCR_BCR(byte);
    
    /* configure DCR register */
    DMA_DCR_REG(DMA_BASE_PTR, ch)=(0
            |DMA_DCR_EADREQ_MASK
            |DMA_DCR_SSIZE(ssize)
            |DMA_DCR_DSIZE(dsize)
            );
    
    /* if enable cycle steal mode */
    if(trans_t&DMA_CYCL_MASK)
        DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_CS_MASK;

    /* if enable source increasement */
    if(trans_t&DMA_SINC_MASK)
        DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_SINC_MASK;

    /* if enable destination increasement */
    if(trans_t&DMA_DINC_MASK)
        DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_DINC_MASK;

    /* set DMAMUX source */
    DMAMUX0_CHCFG(ch)|=DMAMUX_CHCFG_SOURCE(63);

    return 0;
}

int dma_periph_init(int8_t ch, uint8_t periph, uint32_t volatile *sar, uint32_t *dar, uint32_t byte, uint8_t ssize, uint8_t dsize, uint8_t trans_t){
    /* check legallity of input */
    if(ch<DMA_CH0||ch>DMA_CH3)
        return -1;

    /* enable clock gating */
    SIM_SCGC6|=SIM_SCGC6_DMAMUX_MASK; // Enable DMAMUX clock gating
    SIM_SCGC7|=SIM_SCGC7_DMA_MASK; // Enable DMA clock gating

    /* clear pending errors or acknowledge successful transfers */
    DMA_DSR_BCR_REG(DMA_BASE_PTR, ch)|=DMA_DSR_BCR_DONE_MASK;

    /* repeat to confirm */
    DMA_DSR_BCR_REG(DMA_BASE_PTR, ch)|=DMA_DSR_BCR_DONE_MASK;

    /* write source address, destination address, status/byte count */
    DMA_SAR_REG(DMA_BASE_PTR, ch)|=DMA_SAR_SAR(sar);
    DMA_DAR_REG(DMA_BASE_PTR, ch)|=DMA_DAR_DAR(dar);
    DMA_DSR_BCR_REG(DMA_BASE_PTR, ch)|=DMA_DSR_BCR_BCR(byte);
    
    /* configure DCR register */
    DMA_DCR_REG(DMA_BASE_PTR, ch)=(0
            |DMA_DCR_ERQ_MASK
            |DMA_DCR_EADREQ_MASK
            |DMA_DCR_SSIZE(ssize)
            |DMA_DCR_DSIZE(dsize)
            );
    
    /* if enable cycle steal mode */
    if(trans_t&DMA_CYCL_MASK)
        DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_CS_MASK;

    /* if enable source increasement */
    if(trans_t&DMA_SINC_MASK)
        DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_SINC_MASK;

    /* if enable destination increasement */
    if(trans_t&DMA_DINC_MASK)
        DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_DINC_MASK;

    /* set DMAMUX source */
    DMAMUX0_CHCFG(ch)|=DMAMUX_CHCFG_SOURCE(periph);

    return 0;
}

int dmamux_enable(int8_t ch){
    /* check legallity of input */
    if(ch<DMA_CH0||ch>DMA_CH3)
        return -1;

    DMAMUX0_CHCFG(ch)|=DMAMUX_CHCFG_ENBL_MASK;

    return 0;
}

int dma_irq_enable(int8_t ch){
    /* check legallity of input */
    if(ch<DMA_CH0||ch>DMA_CH3)
        return -1;

    DMA_DCR_REG(DMA_BASE_PTR, ch)|=DMA_DCR_EINT_MASK;
    enable_irq(ch);

    return 0;
}

int dma_irq_disable(int8_t ch){
    /* check legallity of input */
    if(ch<DMA_CH0||ch>DMA_CH3)
        return -1;

    disable_irq(ch);

    return 0;
}

int dma_linkcc(int8_t sch, uint8_t type, int8_t ch1, int8_t ch2){
    /* check legallity of input */
    if(sch<DMA_CH0||sch>DMA_CH3
     ||ch1<DMA_CH0||ch1>DMA_CH3
     ||ch2<DMA_CH0||ch2>DMA_CH3)
        return -1;

    DMA_DCR_REG(DMA_BASE_PTR, sch)|=(DMA_DCR_LINKCC(type)
            |DMA_DCR_LCH1(ch1)
            |DMA_DCR_LCH2(ch2)
            );

    return 0;
}
